/** * Copyright 2010 CosmoCode GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.cosmocode.hibernate; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.hibernate.criterion.Conjunction; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Disjunction; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Restrictions; /** * A custom version of {@link Restrictions}. * * @author Willi Schoenborn */ public final class CustomRestrictions { /** * Prevent instantiation. */ private CustomRestrictions() { } /** * Group expressions together in a single disjunction (A or B or C...). * * @param first the first {@link Criterion} * @param second the second {@link Criterion} * @param rest the rest * @return a {@link Criterion} containing all parameters combined in disjunct style */ public static Criterion disjunction(Criterion first, Criterion second, Criterion... rest) { final Disjunction disjunction = Restrictions.disjunction(); disjunction.add(first).add(second); for (Criterion criterion : rest) { disjunction.add(criterion); } return disjunction; } /** * Group expressions together in a single conjunction (A and B and C...). * * @param first the first {@link Criterion} * @param second the second {@link Criterion} * @param rest the rest * @return a {@link Criterion} containing all parameters combined in conjuct style */ public static Criterion conjunction(Criterion first, Criterion second, Criterion... rest) { final Conjunction conjunction = Restrictions.conjunction(); conjunction.add(first).add(second); for (Criterion criterion : rest) { conjunction.add(criterion); } return conjunction; } /** * Apply an "equal" constraint to the named property. * * <p> * Note: This implementation differs from {@link Restrictions#eq(String, Object)} * because it checks for empty strings and applies {@link CustomRestrictions#isEmpty(String)} * instead. * </p> * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value the property should be equals to * @return a new {@link Criterion} */ public static Criterion eq(String propertyName, String value) { return StringUtils.isEmpty(value) ? CustomRestrictions.isEmpty(propertyName) : Restrictions.eq(propertyName, value); } /** * Apply a "not equal" constraint to the named property. * * <p> * Note: This implementation differs from {@link Restrictions#ne(String, Object)} * because it returns {@link CustomRestrictions#isNotEmpty(String)} * in case value is an empty string and returns an logical or expression * of {@link Restrictions#ne(String, Object)} and {@link Restrictions#isNull(String)}. * </p> * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value the property should be not equals to * @return a new {@link Criterion} */ public static Criterion ne(String propertyName, String value) { if (StringUtils.isEmpty(value)) { return CustomRestrictions.isNotEmpty(propertyName); } else { return Restrictions.or( Restrictions.ne(propertyName, value), Restrictions.isNull(propertyName) ); } } /** * Apply an "empty" constraint on the named property. * * <p> * See also {@link StringUtils#isEmpty(String)} * </p> * * @param propertyName the name of the property the constraint should be applied to * @return a new {@link Criterion} */ public static Criterion isEmpty(String propertyName) { return Restrictions.or( Restrictions.eq(propertyName, ""), Restrictions.isNull(propertyName) ); } /** * Apply a "not empty" constraint to the named property. * * <p> * See also {@link StringUtils#isNotEmpty(String)} * </p> * * @param propertyName the name of the property the constraint should be applied to * @return a new {@link Criterion} */ public static Criterion isNotEmpty(String propertyName) { return Restrictions.not(CustomRestrictions.isEmpty(propertyName)); } /** * Apply an "ilike" constraint on the named property. * * <p> * Note: This implementation differs from {@link Restrictions#ilike(String, String, MatchMode)} * because it checks for empty strings and applies {@link CustomRestrictions#isEmpty(String)} * instead. * </p> * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value the property should be similiar to * @param matchMode the {@link MatchMode} being used * @return a new {@link Criterion} */ public static Criterion ilike(String propertyName, String value, MatchMode matchMode) { return StringUtils.isEmpty(value) ? CustomRestrictions.isEmpty(propertyName) : Restrictions.ilike(propertyName, value, matchMode); } /** * Apply an "ilike" constraint on the named property. * * <p> * Note: This implementation differs from {@link Restrictions#ilike(String, Object)} * because it checks for empty strings and applies {@link CustomRestrictions#isEmpty(String)} * instead. * </p> * * <p> * Its equivalent to calling {@link CustomRestrictions#ilike(String, String, MatchMode)} * using {@link MatchMode#ANYWHERE}. * </p> * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value the property should be similiar to * @return a new {@link Criterion} */ public static Criterion ilike(String propertyName, String value) { return ilike(propertyName, value, MatchMode.ANYWHERE); } /** * Apply a "not ilike" constraint on the named property. * * <p> * This implementation handles empty values correctly. * </p> * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value the property should be similiar to * @param matchMode the {@link MatchMode} being used * @return a new {@link Criterion} */ public static Criterion notIlike(String propertyName, String value, MatchMode matchMode) { if (StringUtils.isEmpty(value)) { return CustomRestrictions.isNotEmpty(propertyName); } else { return Restrictions.or( Restrictions.not(Restrictions.ilike(propertyName, value, matchMode)), CustomRestrictions.isEmpty(propertyName) ); } } /** * Apply a "not ilike" constraint on the named property. * * <p> * This implementation handles empty values correctly. * </p> * * <p> * Its equivalent to calling {@link CustomRestrictions#notIlike(String, String, MatchMode)} * using {@link MatchMode#ANYWHERE}. * </p> * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value the property should be similiar to * @return a new {@link Criterion} */ public static Criterion notIlike(String propertyName, String value) { return notIlike(propertyName, value, MatchMode.ANYWHERE); } /** * Apply a "reverse ilike" expression on the named property. * * @see ReverseIlikeExpression * @see PropertyMatchMode * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value which should be similiar to the named property * @param matchMode the {@link PropertyMatchMode} being used * @return a new {@link Criterion} */ public static Criterion reverseIlike(String propertyName, String value, PropertyMatchMode matchMode) { return new ReverseIlikeExpression(propertyName, value, matchMode); } /** * Apply a "reverse ilike" expression on the named property. * * <p> * Its equivalent to calling {@link CustomRestrictions#reverseIlike(String, String, PropertyMatchMode)} * using {@link PropertyMatchMode#ANYWHERE} * </p> * * @see ReverseIlikeExpression * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value which should be similiar to the named property * @return a new {@link Criterion} */ public static Criterion reverseIlike(String propertyName, String value) { return CustomRestrictions.reverseIlike(propertyName, value, PropertyMatchMode.ANYWHERE); } /** * Apply a "not reverse ilike" expression on the named property. * * @see ReverseIlikeExpression * @see PropertyMatchMode * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value which should not be similiar to the named property * @param matchMode the {@link PropertyMatchMode} being used * @return a new {@link Criterion} */ public static Criterion notReverseIlike(String propertyName, String value, PropertyMatchMode matchMode) { return Restrictions.not(CustomRestrictions.reverseIlike(propertyName, value, matchMode)); } /** * Apply a "not reverse ilike" expression on the named property. * * <p> * Its equivalent to calling {@link CustomRestrictions#notReverseIlike(String, String, PropertyMatchMode)} * using {@link PropertyMatchMode#ANYWHERE} * </p> * * @see ReverseIlikeExpression * * @param propertyName the name of the property the constraint should be applied to * @param value the actual value which should not be similiar to the named property * @return a new {@link Criterion} */ public static Criterion notReverseIlike(String propertyName, String value) { return CustomRestrictions.notReverseIlike(propertyName, value, PropertyMatchMode.ANYWHERE); } /** * Apply a "has" constraint to the named enumset property. * * @param <E> the generic enum type * @param propertyName the name of the property the constraint should be applied to * @param e the enum value the named property should contain * @return a new {@link Criterion} */ public static <E extends Enum<E>> Criterion has(String propertyName, E e) { return new EnumSetRestriction<E>(propertyName, "&", e, ">", 0); } /** * Apply a "all" constraint to the named enumset property. * * @param <E> the generic enum type * @param propertyName the name of the property the constraint should be applied to * @param enums the set of enums the named property should contain * @return a new {@link Criterion} */ public static <E extends Enum<E>> Criterion all(String propertyName, Set<E> enums) { return new EnumSetRestriction<E>(propertyName, "&", enums, ">", 0); } /** * Apply a "not has" constraint to the named enumset property. * * @param <E> the generic enum type * @param propertyName the name of the property the constraint should be applied to * @param e the enum value the named property should not contain * @return a new {@link Criterion} */ public static <E extends Enum<E>> Criterion notHas(String propertyName, E e) { return new EnumSetRestriction<E>(propertyName, "&", e, "=", 0); } /** * Apply a "none" constraint to the named enumset property. * * @param <E> the generic enum type * @param propertyName the name of the property the constraint should be applied to * @param enums the set of enums the named property should not contain * @return a new {@link Criterion} */ public static <E extends Enum<E>> Criterion none(String propertyName, Set<E> enums) { return new EnumSetRestriction<E>(propertyName, "&", enums, "=", 0); } }